﻿using NovoDataBase;
using NovoSerDes;
using NovoSerDes.Forms;
using NovoUI;
using Sunny.UI;
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using System.Windows.Forms;
using NovoUI.UserCtrl;
using System.Drawing;
using Newtonsoft.Json;
using System.Reflection;
using System.Threading.Tasks;
using System.Threading;
using NovoUSB2XXX;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
using NovoSerDes.Funcs;
using System.Xml.Serialization;
using System.Windows.Forms.VisualStyles;
using System.Security.Permissions;
using static NovoSerDes.Config;


namespace NovoSerDesEva
{
    public partial class MainForm : UIForm
    {
        private static SerDesComm myUsbDev = null;// = new SerDesComm(0);
        private static List<NovoDataSet> myDataSetList = null;
        private static List<RegisterMap> myRegisterMapList = null;
        private static List<SerDesComm> mySerDesCommList = null;
        private static NovoDataSet myDataSet = null;
        private static Dictionary<string, SerDesComm> IniSerPairs = new Dictionary<string, SerDesComm>();
        private TreeNode configuration;

        private Config config;
        private Log log;

        private static ConfigState configState;

        public static ConfigState ConfigState
        {
            get { return configState; }
        }

        private AddressMeditor mediatorA = new AddressMeditor();
        private AddressMeditor mediatorB = new AddressMeditor();
        private AddressMeditor mediatorC = new AddressMeditor();
        private AddressMeditor mediatorD = new AddressMeditor();
        private AddressMeditor mediatorDes = new AddressMeditor();

        private USBDeviceMeditor USBDeviceMeditorA = new USBDeviceMeditor();
        private USBDeviceMeditor USBDeviceMeditorB = new USBDeviceMeditor();
        private USBDeviceMeditor USBDeviceMeditorC = new USBDeviceMeditor();
        private USBDeviceMeditor USBDeviceMeditorD = new USBDeviceMeditor();
        private USBDeviceMeditor USBDeviceMeditorDes = new USBDeviceMeditor();

        private Dictionary<string, AddressMeditor> mediatorDictionary;
        private Dictionary<string, USBDeviceMeditor> usbDeviceMedtorDictory;

        static int pageIndex = 9000;
        TreeNode serializeNode;
        TreeNode deserializeNode;
        public MainForm()
        {
            InitializeComponent();           
            this.bar_version.Text = this.Text;
            int pageIndex = 1000;
            //设置uiNavBar1设置节点，也可以在Nodes属性里配置
            uiNavBar1.Nodes.Add("Main");
            uiNavBar1.Nodes.Add("Tools");
            uiNavBar1.Nodes.Add("Operation");

            uiNavBar1.SetNodePageIndex(uiNavBar1.Nodes[0], pageIndex);
            uiNavBar1.SetNodeSymbol(uiNavBar1.Nodes[0], 61451, 24, pageIndex);

            //TreeNode parent = uiNavMenu1.CreateNode("Main", 61451, 24, pageIndex);
            TreeNode parent = uiNavMenu1.CreateNode("Main", pageIndex);
            parent.ImageIndex = 4;
            config = new Config();
            config.ComboxDataChanged += IniSerDesInit;
            config.AddPageClicked += PageChange;
            //config.ComboxDataChanged += Config_ComboxChange;
            config.OnSetAddr += setAddr;
            config.RefreshComboxDevAndIICMode();
            config.MediatorA = mediatorA;
            config.MediatorB = mediatorB;
            config.MediatorC = mediatorC;
            config.MediatorD = mediatorD;
            config.MediatorDes = mediatorDes;
            config.UsbDeviceMetorA = USBDeviceMeditorA;
            config.UsbDeviceMetorB = USBDeviceMeditorB;
            config.UsbDeviceMetorC = USBDeviceMeditorC;
            config.UsbDeviceMetorD = USBDeviceMeditorD;
            config.UsbDeviceMetorDes = USBDeviceMeditorDes;
            uiNavMenu1.CreateChildNode(parent, AddPage(config, ++pageIndex));
       

            pageIndex = 2000;
            uiNavBar1.SetNodePageIndex(uiNavBar1.Nodes[1], pageIndex);
            uiNavBar1.SetNodeSymbol(uiNavBar1.Nodes[1], 57398);
            //parent = uiNavMenu1.CreateNode("Tool", 57398, 24, pageIndex);
            parent = uiNavMenu1.CreateNode("Tool", pageIndex);
            parent.ImageIndex = 3;
            uiNavMenu1.CreateChildNode(parent, AddPage(new Erro_Status(), ++pageIndex));
            //uiNavMenu1.CreateChildNode(parent,AddPage(new form_Serializer(),++pageIndex));
            //uiNavMenu1.CreateChildNode(parent, AddPage(new RegisterReadWrite(), ++pageIndex));
            uiNavMenu1.CreateChildNode(parent, AddPage(new CFGSetup(), ++pageIndex));
            //uiNavMenu1.CreateChildNode(parent, AddPage(new PinMapSetup(), ++pageIndex));
            uiNavMenu1.CreateChildNode(parent, AddPage(new BandwidthCalculator(), ++pageIndex));
            uiNavMenu1.CreateChildNode(parent, AddPage(new VPG(), ++pageIndex));
            uiNavMenu1.CreateChildNode(parent, AddPage(new OtherTools(), ++pageIndex));

            //pageIndex = 9000;
            //uiNavBar1.SetNodeSymbol(uiNavBar1.Nodes[2], 361642);
            //configuration = uiNavMenu1.CreateNode("configuration", 361642,23, pageIndex);

            pageIndex = 3000;
            //parent = uiNavMenu1.CreateNode("Log", 57511, 24, ++pageIndex);
            parent = uiNavMenu1.CreateNode("Log", ++pageIndex);
            parent.ImageIndex = 2;
            log = new Log();
            uiNavMenu1.CreateChildNode(parent,AddPage(log,++pageIndex));


            pageIndex = 9000;
            serializeNode = uiNavBar1.CreateChildNode(uiNavBar1.Nodes[2], "Save Project", ++pageIndex);
            deserializeNode = uiNavBar1.CreateChildNode(uiNavBar1.Nodes[2], "Load Project", ++pageIndex);

            mediatorDictionary = new Dictionary<string, AddressMeditor>
            {
                { "NLS9116A", mediatorA },
                { "NLS9116B", mediatorB },
                { "NLS9116C", mediatorC },
                { "NLS9116D", mediatorD },
                { "NLS9246", mediatorDes }
            };

            usbDeviceMedtorDictory = new Dictionary<string, USBDeviceMeditor>
            {
                { "NLS9116A", USBDeviceMeditorA },
                { "NLS9116B", USBDeviceMeditorB },
                { "NLS9116C", USBDeviceMeditorC },
                { "NLS9116D", USBDeviceMeditorD},
                { "NLS9246", USBDeviceMeditorDes }
            };
        }
        
        #region
        public interface ISerDesInitStrategy
        {
            string getName { get; set; }
            void InitializeSerDesComm(UIComboBox comboBox, List<SerDesComm> serDesCommList, int selectedIndex);
        }

        public class DevAStrategy : ISerDesInitStrategy
        {
           
            public void InitializeSerDesComm(UIComboBox comboBox, List<SerDesComm> serDesCommList, int selectedIndex)
            {
                IniSerPairs["NLS9116A"] = serDesCommList[selectedIndex];
            }
            private string comboxName;
            public string getName
            {
                get { return comboxName; }
                set {  comboxName = value; }
            }
        }

        public class DevBStrategy : ISerDesInitStrategy
        {
            public void InitializeSerDesComm(UIComboBox comboBox, List<SerDesComm> serDesCommList, int selectedIndex)
            {
                IniSerPairs["NLS9116B"] = serDesCommList[selectedIndex];
            }
            private string comboxName;
            public string getName
            {
                get { return comboxName; }
                set { comboxName = value; }
            }
        }

        public class DevCStrategy : ISerDesInitStrategy
        {
            public void InitializeSerDesComm(UIComboBox comboBox, List<SerDesComm> serDesCommList, int selectedIndex)
            {
                IniSerPairs["NLS9116C"] = serDesCommList[selectedIndex];
            }
            private string comboxName;
            public string getName
            {
                get { return comboxName; }
                set { comboxName = value; }
            }
        }

        public class DevDStrategy : ISerDesInitStrategy
        {
            public void InitializeSerDesComm(UIComboBox comboBox, List<SerDesComm> serDesCommList, int selectedIndex)
            {
                IniSerPairs["NLS9116D"] = serDesCommList[selectedIndex];
            }
            private string comboxName;
            public string getName
            {
                get { return comboxName; }
                set { comboxName = value; }
            }
        }

        public class DevDesStrategy : ISerDesInitStrategy
        {
            public void InitializeSerDesComm(UIComboBox comboBox, List<SerDesComm> serDesCommList, int selectedIndex)
            {
                IniSerPairs["NLS9246"] = serDesCommList[selectedIndex];
            }
            private string comboxName;
            public string getName
            {
                get { return comboxName; }
                set { comboxName = value; }
            }
        }

        public class SerDesInitStrategyDictionary
        {
            private readonly static Dictionary<string, ISerDesInitStrategy> _strategyDictionary = new Dictionary<string, ISerDesInitStrategy>();

            public SerDesInitStrategyDictionary()
            {
                // 将不同的策略类加入字典
                _strategyDictionary["combox_devA"] = new DevAStrategy();
                _strategyDictionary["combox_devB"] = new DevBStrategy();
                _strategyDictionary["combox_devC"] = new DevCStrategy();
                _strategyDictionary["combox_devD"] = new DevDStrategy();
                _strategyDictionary["combox_devDes"] = new DevDesStrategy();
            }

            public static bool AddStrategy(ISerDesInitStrategy strategy)
            {
                if(_strategyDictionary.ContainsKey(strategy.getName)) { return false; }
                _strategyDictionary[strategy.getName] = strategy;
                return true;
            }

            public ISerDesInitStrategy GetStrategy(string comboBoxName)
            {
                if (_strategyDictionary.ContainsKey(comboBoxName))
                {
                    return _strategyDictionary[comboBoxName];
                }
                else
                {
                    throw new ArgumentException("Invalid comboBox name");
                }
            }                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
        }
        #endregion
        private bool setAddr(string serDesComm,string add)
        {
            if(IniSerPairs.ContainsKey(serDesComm))//改变每个芯片中CH347对应的ChipAddress
            {
                byte DevAddr = Convert.ToByte(add.Replace("0x", ""),16);
                IniSerPairs[serDesComm].CurrentDevAddr = DevAddr;
                return true;
            }
            return false;
        }
        /// <summary>
        /// 每个NS9116设置相对应的CH347
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void IniSerDesInit(object sender, EventArgs e)
        {
            UIComboBox combox = (UIComboBox)sender;
            int idx = combox.SelectedIndex;

            SerDesInitStrategyDictionary strategyDictionary = new SerDesInitStrategyDictionary();
            ISerDesInitStrategy strategy = strategyDictionary.GetStrategy(combox.Name);
            if(idx >= 0)
            {
                strategy.InitializeSerDesComm(combox, mySerDesCommList, idx);//添加新的键值对，每个芯片对应一个CH347
            }
            
        }

        public static Dictionary<string, SerDesComm> IniSerCommPairs
        {
            get { return IniSerPairs; }
        }

        private void Config_ComboxChange(object sender, EventArgs e)
        {
            UIComboBox combox = (UIComboBox)sender;
            int index = combox.SelectedIndex;
            if(index  < 0) { return; }
            myUsbDev = mySerDesCommList[index];
        }

        public static SerDesComm GetSerDesComm()
        {
            if (myUsbDev == null)
            {
                myUsbDev = new SerDesComm();
                Process currentProc = Process.GetCurrentProcess();
                Process[] tempPorcList = Process.GetProcessesByName(currentProc.ProcessName);
                //maxUSBDevCount = tempPorcList.Length;
                if (tempPorcList.Length >= 2)
                {
                    //string devName = myUsbDev.GetDevName();
                    //setIICDevice = new Form_SetIICDevice(myUsbDev.DevID, maxUSBDevCount, devName, myUsbDev.CurrentDevAddr,
                    //    myUsbDev.I2C_CFG.ClockSpeedHz, myUsbDev.I2C_CFG.EnablePu);
                    //setIICDevice.FormClosingEvent += new Form_SetIICDevice.SetIICDevClosingEventHandler(SetIICDevClosingEvent);
                    //setIICDevice.ShowDialog();
                }
                else
                {
                    myUsbDev.OpenDevice(0);
                }
                return myUsbDev;
            }
            return myUsbDev;
        }

        public static SerDesComm GetSetDesComm
        {
            get { return myUsbDev;}
        }

        public static NovoDataSet DataSet
        {
            get { return myDataSet; }
        }
        public static List<NovoDataSet> GetDataSetList()
        {
            if(myDataSetList == null)
            {
                string projPath = System.IO.Path.Combine(Application.StartupPath, "nsproj file");
                if (Directory.Exists(projPath))
                {
                    myDataSetList = new List<NovoDataSet>();
                    myRegisterMapList = new List<RegisterMap>();
                    string[] nsprojFiles = Directory.GetFiles(projPath, "*.nsproj");
                    foreach (string filePath in nsprojFiles)
                    {
                        IFormatter formatter = new BinaryFormatter();
                        Stream destream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
                        NovoDataSet dataSet = formatter.Deserialize(destream) as NovoDataSet;
                        dataSet.DevInfo = ExcelToRegMap.DecodeDeviceInfo(null);
                        dataSet.DevInfo.FilePath = filePath;

                        destream.Close();
                        myDataSetList.Add(dataSet);
                    }
                }
                else
                {
                    //UIMessageDialog.ShowErrorDialog(Control.FindForm(), "找不到nsproj文件");
                    UIMessageDialog.ShowErrorDialog(ActiveForm, "找不到nsproj文件");
                }
            }
            return myDataSetList;
        }

        public static List<SerDesComm> GetSerDesCommList()
        {
            if(mySerDesCommList == null)
            {
                mySerDesCommList = new List<SerDesComm>();
                int devCnt = 0;
                SerDesComm comm = new SerDesComm();
                for(int i = 0; i < 5; ++i)
                {
                    if (comm.OpenDevice(i)){
                        ++devCnt;
                    }
                }
                for(int i = 0; i < devCnt; i++)
                {
                    SerDesComm serDesComm = new SerDesComm();
                    Console.WriteLine("{0} is {1}",i, serDesComm.OpenDevice(i));
                    //serDesComm.SetDevID();
                    mySerDesCommList.Add(serDesComm);                    
                    Console.WriteLine(serDesComm.ToString());
                }
            }
            return mySerDesCommList;

        }
        

        public void CreatChildPage(string name)
        {
            //string configFilePath = "D:\\C#\\NovoSense-NovoserDesEva-Michael\\NovoSerDesEva\\MainForm\\config.json"; // 配置文件路径
            //if (!File.Exists(configFilePath))
            //{
            //    UIMessageDialog.ShowErrorDialog(FindForm(), "找不到Json配置文件");
            //    return;
            //}
            //string json = File.ReadAllText(configFilePath);
            //List<PageConfig> pages = JsonConvert.DeserializeObject<List<PageConfig>>(json);

            //TreeNode node = uiNavMenu1.CreateNode(name, 362171,24,++pageIndex);
            TreeNode node = uiNavMenu1.CreateNode(name, ++pageIndex);
            node.ImageIndex = 0;
            
            node.Name = name;
            Script_Form script;
            RegisterReadWrite regRdWr;

            //script = new Script_Form(name, mediatorDictionary[name]);
            script = new Script_Form(name, mediatorDictionary[name], usbDeviceMedtorDictory[name]);
            script.Name = name;
            script.Text = "Script";
            uiNavMenu1.CreateChildNode(node, AddPage(script, ++pageIndex));

            regRdWr = new RegisterReadWrite(name);
            regRdWr.Meditor = mediatorDictionary[name];
            regRdWr.UsbDeviceMetor = usbDeviceMedtorDictory[name];
            regRdWr.ConfigState = configState;
            InitRegRWAddr += regRdWr.InitRegRWAddr;
            regRdWr.Name = name;
            regRdWr.Text = "Reg RW";
            uiNavMenu1.CreateChildNode(node, AddPage(regRdWr, ++pageIndex));
            //RegMap_Form regMap = new RegMap_Form(name);
            RegMap_Form regMap = new RegMap_Form(name, usbDeviceMedtorDictory[name]);
            
            
            regMap.Name = name;
            regMap.Text = "RegMap";
           
            
            uiNavMenu1.CreateChildNode(node, AddPage(regMap, ++pageIndex));
            if (IniSerCommPairs.ContainsKey(name))
            {
                Form_RegDump regDump = new Form_RegDump(IniSerCommPairs[name], myDataSet.RegMap, myDataSet.DefaultRegMap, IniSerCommPairs[name].CurrentDevAddr);
                regDump.Name = name;
                regDump.Text = "RegDump";
                regDump.Meditor = mediatorDictionary[name];
                regDump.UsbDeviceMetor = usbDeviceMedtorDictory[name];
                uiNavMenu1.CreateChildNode(node, AddPage(regDump, ++pageIndex));
            }
            
            uiNavMenu1.CreateChildNode(node,AddPage(new PinMapSetup(), ++pageIndex));
        }       

        public class PageConfig
        {
            public string Name { get; set; }
            public string Type { get; set; }
        }
        private Dictionary<string, string> switchToFileMap = new Dictionary<string, string>()
        {
            { "uiSwitchA", "NLS9116A" },
            { "uiSwitchB", "NLS9116B" },
            { "uiSwitchC", "NLS9116C" },
            { "uiSwitchD", "NLS9116D" },
            { "uiSwitchDes", "NLS9246" }
        };
        private void PageChange(object sender,bool value)
        {
            UISwitch sw = (UISwitch)sender;
            string name = null;
            if (switchToFileMap.ContainsKey(sw.Name))
            {
                name = switchToFileMap[sw.Name];
            }
            myDataSet = null;
            foreach (var set in myDataSetList)
            {
                if (set.DevInfo.FilePath.Contains(name))
                {
                    myDataSet = set;
                }
            }
            if (value == true)
            {
                this.CreatChildPage(name);
            }
            else
            {
                this.RemoveChildPage(name);
            }

        }

        public void RemoveChildPage(string name)
        {
            foreach (TreeNode node in this.uiNavMenu1.Nodes)
            {
                // 确保节点不为空引用
                if (node != null)
                {
                    // 处理每个子节点 node
                    if (node.Name == name)
                    {
                       uiNavMenu1.Nodes.Remove(node);
                        break; // 移除节点后退出循环
                    }
                }
            }
            //// 初始化 pageIndex 为 -1，表示未找到
            //int pageIndex = -1;

            //// 遍历 TabPages 集合查找特定名称的页，并获取其索引
            //for (int i = 0; i < uiTabControl1.TabPages.Count; i++)
            //{
            //    if (uiTabControl1.TabPages[i].Name == name)
            //    {
            //        pageIndex = i; // 找到对应名称的页，获取其索引
            //        break; // 找到后退出循环
            //    }
            //}
            //uiTabControl1.RemovePage(pageIndex);
        }


        private void uiNavBar1_MenuItemClick(string itemText, int menuIndex, int pageIndex)
        {
            switch(menuIndex)
            {
                case 4:
                    UIStyle style = (UIStyle)pageIndex;
                    if (pageIndex < UIStyle.Colorful.Value()) ;
                    //StyleManager.Style = style;
                    else
                        uiNavMenu1.SelectPage(pageIndex);
                    break;
                default:
                    uiNavMenu1.SelectPage(pageIndex);
                    break;
            }
        }

        #region Auto Dongle Detect

        public const int WM_DEVICECHANGE = 537;
        private const int WM_CH347DevArrive = 0x0010;
        private const int WM_CH347DevRemove = 0x0011;

        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);
            if (m.Msg == WM_DEVICECHANGE)
            {
                lock (mySerDesCommList)
                {
                    int devCnt = mySerDesCommList.Count;
                    bool isAllOpen = true;
                    foreach (var serDesComm in mySerDesCommList)
                    {
                        if(!serDesComm.ReOpenDevice())
                            isAllOpen = false;
                    }
                    if(isAllOpen == true)
                    {
                        SerDesComm ser = new SerDesComm();
                        if (ser.OpenDevice(devCnt))
                        {
                            mySerDesCommList.Add(ser);                            
                            config.UpdataComboxData();
                        }                       
                    }
                }
                
            }


        }

        #endregion Auto Dongle Detect

        public event EventHandler<bool> InitRegRWAddr;
        private void uiNavBar1_NodeMouseClick(TreeNode node, int menuIndex, int pageIndex)
        {
            if (node == serializeNode)
            {
                SaveFileDialog saveFileDialog = new SaveFileDialog();
                saveFileDialog.Title = "save project file...";
                saveFileDialog.Filter = "NSPROJ(.nsproj)|*.nsproj";
                string projectFolderPath = Path.Combine(Application.StartupPath, "project");

                if (!Directory.Exists(projectFolderPath))
                {
                    Directory.CreateDirectory(projectFolderPath);
                }
                saveFileDialog.InitialDirectory = System.IO.Path.Combine(Application.StartupPath, "project");

                if (saveFileDialog.ShowDialog() == DialogResult.OK)
                {                    
                    string filePath = saveFileDialog.FileName;
                    configState = new ConfigState();
                    //XmlSerializer xmlSerializer = new XmlSerializer(typeof(ConfigState));
                    config.SaveConfigState(filePath, configState);
                    InitRegRWAddr?.Invoke(null, true);
                    configState.ConfigDataSetList = myDataSetList;
                    IFormatter formatter = new BinaryFormatter();             //创建一个文件流
                    Stream stream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
                    formatter.Serialize(stream, configState);
                    stream.Close();

                }
            }
            else if(node == deserializeNode)
            {
                OpenFileDialog openFileDialog = new OpenFileDialog();
                openFileDialog.Title = "open an project file and update infomations to GUI...";
                openFileDialog.Filter = "NSPROJ(.nsproj)|*.nsproj";
                openFileDialog.InitialDirectory = System.IO.Path.Combine(Application.StartupPath, "project");

                if (openFileDialog.ShowDialog() == DialogResult.OK)
                {
                    string filePath = openFileDialog.FileName;
                    IFormatter formatter = new BinaryFormatter();
                    Stream destream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
                    configState = formatter.Deserialize(destream) as ConfigState;
                    if(configState == null)
                    {
                        UIMessageDialog.ShowErrorDialog(FindForm(), "请打开正确的工程文件");
                        return;
                    }
                    for (int i = 0; i < myDataSetList.Count; ++i)
                    {
                        for(int j = 0; j < configState.ConfigDataSetList.Count; ++j)
                        {
                            if (myDataSetList[i].DevInfo.FilePath == configState.ConfigDataSetList[j].DevInfo.FilePath)
                            {
                                myDataSetList[i] = configState.ConfigDataSetList[j];
                            }
                        }
                    }
                    config.LoadConfigState(filePath, configState);
                    InitRegRWAddr?.Invoke(null, false);
                    destream.Close();
                }
            }              
        }

        
    }

}